home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / system / csh4.zip / MAIN.C < prev    next >
C/C++ Source or Header  |  1985-09-05  |  12KB  |  516 lines

  1. #include <debug.h>
  2. #include <stdio.h>
  3. #include <ctype.h>
  4. #include <signal.h>
  5. #include <fcntl.h>
  6. #include <setjmp.h>
  7. typedef struct        /* used to find builtin commands */
  8. {
  9.     char *cmdname;
  10.     int (*func)();
  11. } builtin;
  12.  
  13. extern builtin commands[];
  14. extern char histerr[];
  15. extern int j,hiscount;
  16. extern char *history[];
  17. extern int histsize;
  18. extern int numcmds;
  19.  
  20. char *version = "SHELL VERSION 1.1 Kent Williams";
  21.  
  22. jmp_buf env;
  23.  
  24. char *pipename[] =
  25. {
  26.     "\\shtmp1",
  27.     "\\shtmp2"
  28. };
  29.  
  30. char cmdbuf[512];
  31. int  currname = 0;
  32. int result = 0;
  33.  
  34. main(argc,argv)
  35.     char *argv[];
  36. {
  37.     register int i;
  38.     int repeat, quiet, state, inpipe = 0;
  39.     static char localbuf[256];
  40.     static char histbuf[256];
  41.     static char tail[256];
  42.     int histindex,argindex,takeline;
  43.     char *local = localbuf;
  44.     register char *current,*curr_save;
  45.     char *ntharg(), *argptr;
  46.     char *savestr();
  47.  
  48.     signal(SIGINT,SIG_IGN);    /* ignore breaks */
  49.  
  50.     quiet = !isatty(0);        /* quiet = batch shell */
  51.  
  52.     /* initialize local environment */
  53.     init_env();
  54.     /* command interpreter loop */
  55.     for(j=0;;)
  56.     {
  57.         /* kill tmp files */
  58.         unlink(pipename[0]); unlink(pipename[1]);
  59.  
  60.         hiscount = j % histsize; /* hiscount is current position in history */
  61.         if(!quiet)
  62.             fprintf(stderr,"%d%% ",j);
  63.  
  64. /*
  65.  * The following code simply reads a line from standard input.
  66.  * It is so complicated because when you save the standard stream
  67.  * files and execute another program/command, standard input is
  68.  * left in an uncertain state - the FILE stdin seems to be at EOF,
  69.  * even when standard input is associated with the console, and
  70.  * cr/lf combinations show up as line terminators, whereas usually
  71.  * only linefeeds get placed in the input stream.
  72.  * WHY? beats me.  Something could be wrong with
  73.  *  1. AZTEC C runtime
  74.  *  2. PCDOS
  75.  *  3. Me
  76.  *  4. All three, or permutations of 1-3 reducto ad absurdum.
  77.  * All I know is this works
  78.  */
  79.         /* clear command buffer so string read is null terminated */
  80.         setmem(cmdbuf,sizeof(cmdbuf),0);
  81.         for (current = cmdbuf;;current++)
  82.         {
  83.             int readresult;
  84.             if ((readresult = read(0,current,1)) == 0 ||
  85.                 readresult == -1)
  86.             {
  87.                 exit (0);
  88.             }
  89.             if (*current == '\r')
  90.             {
  91.                 if ((readresult = read(0,current,1)) == 0 ||
  92.                     readresult == -1)
  93.                 {
  94.                     exit (0);
  95.                 }
  96.                 *current = '\0';
  97.                 break;
  98.             }
  99.             else if (*current == '\n')
  100.             {
  101.                 *current = '\0';    /* terminate string */
  102.                 break;
  103.             }
  104.         }
  105.         current = cmdbuf;    /* point current at start of buffer */
  106. /*
  107.  * end of input weirdness
  108.  */
  109.         /* if we're recycling history strings, free previous one */
  110.         if (history[hiscount])
  111.             free(history[hiscount]);
  112.  
  113.         /* save current in history array */
  114.         history[hiscount] = savestr(current);
  115.  
  116. #define CHAR            -1
  117. #define PIPE            -2
  118. #define DOUBLEQUOTES     -3
  119. #define SINGLEQUOTES     -4
  120. #define EMIT             -5
  121. #define COMPOUND         -6
  122. #define DONE            -7
  123. #define EATWHITESPACE    -8
  124. #define HISTORY            -9
  125. #define CONTINUE        -0xA
  126.  
  127.         /* parse command for compound statements and pipes */
  128.         state = EATWHITESPACE;
  129.         local = localbuf;
  130.         setmem(localbuf,sizeof(localbuf),0);    /* clear buffer */
  131.         while (state != DONE && state != CONTINUE)
  132.         {
  133.             switch(state)
  134.             {
  135.             case CHAR:
  136.                 switch(*current)
  137.                 {
  138.                 case '\0':
  139.                     *local = '\0';
  140.                     state = EMIT;
  141.                     break;
  142.                 case '"' :
  143.                     state = DOUBLEQUOTES;
  144.                     *local++ = *current;
  145.                     break;
  146.                 case '/' :
  147.                     *local++ = '\\';
  148.                     break;
  149.                 case '\'':
  150.                     state = SINGLEQUOTES;
  151.                     *local++ = *current;
  152.                     break;
  153.                 case '\\':
  154.                     *local++ = *++current;
  155.                     break;
  156.                 case ';':
  157.                     *local = '\0';
  158.                     state = COMPOUND;
  159.                     break;
  160.                 case '|':
  161.                     *local = '\0';
  162.                     state = PIPE;
  163.                     break;
  164.                 case '!':
  165.                     state = HISTORY;
  166.                     break;
  167.                 default:
  168.                     *local++ = *current;
  169.                     break;
  170.                 }
  171.                 current++;
  172.                 break;
  173.             case EMIT:
  174.                 if (inpipe)
  175.                 {
  176.                     inpipe = 0;
  177.                     strcat(localbuf," < ");
  178.                     strcat(localbuf,pipename[currname]);
  179.                 }
  180.                 command(localbuf);
  181.                 state = DONE;
  182.                 break;
  183.             case COMPOUND:
  184.                 if (inpipe)
  185.                 {
  186.                     inpipe = 0;
  187.                     strcat(localbuf," < ");
  188.                     strcat(localbuf,pipename[currname]);
  189.                 }
  190.                 command(localbuf);
  191.                 local = localbuf;
  192.                 setmem(localbuf,sizeof(localbuf),0);    /* clear buffer */
  193.                 state = EATWHITESPACE;
  194.                 break;
  195.             case SINGLEQUOTES:
  196.                 switch (*current)
  197.                 {
  198.                 case '\0':
  199.                     write(2,"No closing quotes!!\r\n",21);
  200.                     state = DONE;
  201.                     break;
  202.                 case '\'':
  203.                     state = CHAR;
  204.                     *local++ = *current;
  205.                     break;
  206. #ifdef TEST
  207.                 case '\\':
  208.                     *local++ = *++current;
  209.                     break;
  210. #endif
  211.                 default:
  212.                     *local++ = *current;
  213.                 }
  214.                 current++;    
  215.                 break;
  216.             case DOUBLEQUOTES:
  217.                 switch(*current)
  218.                 {
  219.                 case '\0':
  220.                     write(2,"No closing quotes!!\r\n",21);
  221.                     state = DONE;
  222.                     break;
  223.                 case '"':
  224.                     state = CHAR;
  225.                     break;
  226. #ifdef TEST
  227.                 case '\\':
  228.                     ++current;
  229.                     break;
  230. #endif
  231.                 }
  232.                 *local++ = *current++;
  233.                 break;
  234.             case HISTORY:
  235.                 /* handle history substitutions */
  236.                 setmem(histbuf,sizeof(histbuf),0);    /* clear buffer */
  237.  
  238.                 /* save current pointer into command buffer */
  239.                 curr_save = current;
  240.                 DEBUGGER(fprintf(stderr,"current = %s\n",current););
  241.  
  242.                 /* copy command head */
  243.                 strncpy(histbuf,cmdbuf,(int)(current-cmdbuf)-1);
  244.  
  245.                 /* takeline means take all arguments past current one */
  246.                 takeline = 0;
  247.  
  248.                 /* parse history expression */
  249.                 switch (*current)
  250.                 {
  251.                 case '!':    /* last command line */
  252.  
  253.                 DEBUGGER(fprintf(stderr,"last command\n"););
  254.                     if (j)    /* special case first time through */
  255.                     {
  256.                         histindex = hiscount ? hiscount - 1 : histsize - 1;
  257.                     }
  258.                     else
  259.                     {
  260.                         /* force error condition */
  261.                         write(2,histerr,strlen(histerr));
  262.                         state = CONTINUE;
  263.                     }
  264.                     current++;    /* point to next */
  265.                     break;
  266.                 case '-':        /* negative (relative #) */
  267.                 /* a particular numbered command */
  268.                 case '0':
  269.                 case '1':
  270.                 case '2':
  271.                 case '3':
  272.                 case '4':
  273.                 case '5':
  274.                 case '6':
  275.                 case '7':
  276.                 case '8':
  277.                 case '9':
  278.                     DEBUGGER(fprintf(stderr,\
  279.                     "numbered command current = %s\n",current););
  280.                     /* repeat numbered command */
  281.                     repeat = atoi(current);
  282.                     if (repeat < 0)    /* handle relative addressing */
  283.                         repeat += j;
  284.                     /* if command is within range */
  285.                     if ((j - repeat) <= histsize && repeat < j)
  286.                     {
  287.                         histindex = repeat % histsize;
  288.                     }
  289.                     else
  290.                     {
  291.                         state = CONTINUE;
  292.                     }
  293.  
  294.                     DEBUGGER(fprintf(stderr,"number %d\n",histindex););
  295.                     while(isdigit(*current)||*current=='-')
  296.                         ++current;
  297.                     break;
  298.                 default:
  299.                     write(2,"Bad history expression\r\n",24);
  300.                     state = CONTINUE;
  301.                     break;
  302.                 }
  303.                 if (state == CONTINUE)    /* error state */
  304.                     break;    
  305.                 /* look for particular argument substitutions */
  306.                 DEBUGGER(fprintf(stderr,\
  307.                     "looking for colon expression, current = %s\n",current););
  308.                 switch (*current)
  309.                 {
  310.                 /* we want the whole enchilada */
  311.                 case '\0':
  312.                 case '\t':
  313.                 case '\r':
  314.                 case '\n':
  315.                 case ' ':
  316.                     DEBUGGER(fprintf(stderr,"whole cmdline\n"););
  317.                     DEBUGGER(fprintf(stderr,"current = %s\n",current););
  318.                     strcat(histbuf,history[histindex]);
  319.                     state = CHAR;
  320.                     break;
  321.                 case ':':
  322.                     ++current;    /* point past colon */
  323.                 DEBUGGER(fprintf(stderr,"current = %s\n",current););
  324.                     switch (*current)
  325.                     {
  326.                     case '^':
  327.                         argindex = 1;
  328.                         ++current;
  329.                         break;
  330.                     case '0':
  331.                     case '1':
  332.                     case '2':
  333.                     case '3':
  334.                     case '4':
  335.                     case '5':
  336.                     case '6':
  337.                     case '7':
  338.                     case '8':
  339.                     case '9':
  340.                         /* index of argument */ 
  341.                         argindex = atoi(current);
  342.                         DEBUGGER(fprintf(stderr,"%s = %d\n",current,argindex););
  343.                         while(isdigit(*current))
  344.                             ++current;
  345.                         if (*current = '*')
  346.                         {
  347.                             takeline = 1;
  348.                             current++;
  349.                         }
  350.                         break;
  351.                     case '$':
  352.                         argindex = lastarg(history[histindex]);
  353.                         current++;
  354.                         break;
  355.                     case '*':
  356.                         takeline = 1;    /* take arg 1 t